#ifndef GROWARRAY_H_INCLUDED
#define GROWARRAY_H_INCLUDED


#define GROWAHEAD 15

template <class T>
class GrowArray {

public:
    GrowArray(const GrowArray<T>& src){
        pCount=0;
        pSize = 0;
        pData = NULL;
        pIsOwner = false;
        pAheadSize = GROWAHEAD;
        operator =(src);
    };

    GrowArray(){
        pCount=0;
        pSize = 0;
        pData = NULL;
        pIsOwner = false;
        pAheadSize = GROWAHEAD;
    };

    virtual ~GrowArray(){
        Clear();
    };


    int Add(T* data){
        if(pCount >= pSize)
            Grow();
        pData[pCount] = data;
        pCount ++;
		return(pCount-1);
    };

    T* Add(const T& data){
#ifdef __WXWINDOWS__
    wxASSERT_MSG(pIsOwner,_T("Must be owner"));
#endif
        T* tmp = new T;
		*tmp = data;
		Add(tmp);
		return(tmp);
    };


    int Index(const T* ptr){
        for(int ct=0;ct<pCount;ct++)
        {
            if(ptr == pData[ct])
                return((int)ct);
        }
        return(-1);
    }

    T* operator[](const int index) const{
#ifdef __WXWINDOWS__
        wxCHECK_MSG((unsigned int)index < (unsigned int)pCount,NULL,_T("Index out of range"));
#endif
        return(pData[index]);
    };

    GrowArray<T>& operator = (const GrowArray<T>& src)
    {
        Clear();
        pIsOwner = src.pIsOwner;
        int n = src.pCount;
        for(int ct=0;ct < n; ct++)
        {
            if(pIsOwner)
            {
                Add(*src[ct]);
            }else
            {
                Add(src[ct]);
            }
        }
        return(*this);
    }

    void Delete(const T* ptr){
        Delete(Index(ptr));
    };

    void Delete(const int index){
        if((unsigned int)index >= (unsigned int)pCount)
            return;
        delete pData[index];
        Remove(index);
    };

	void Swap(const int i1,const int i2)
	{
	    if((unsigned int)i1 >= (unsigned int)pCount)
            return;
	    if((unsigned int)i2 >= (unsigned int)pCount)
            return;
		T* tmp = pData[i1];
		pData[i1] = pData[i2];
		pData[i2] = tmp;
	}

	void Remove(const T* ptr){
        Remove(Index(ptr));
    };

    void Remove(const int index){
        if((unsigned int)index >= (unsigned int)pCount)
            return;
        for(int ct=index;ct<pCount -1;ct++)
            pData[ct] = pData[ct+1];
        pCount --;
    };

    void Clear(void){
        if(pIsOwner)
        {
			for(int ct=0;ct<pCount;ct++)
			{
    			delete pData[ct];
			}
	    }
        pCount=0;
        delete[] pData;
        pSize=0;
        pData = NULL;
    };

	void Grow(void){Grow(pAheadSize);}

    void Grow(size_t amount){
        pSize += amount;
        T** tmp = new T*[pSize];
        for(int ct=0;ct<pCount;ct++)
        {
            tmp[ct]=pData[ct];
        }
        if(pData)
            delete[] pData;
        pData = tmp;
    }


    bool IsOwner(void){
        return(pIsOwner);
    }


    void IsOwner(bool status){
        pIsOwner = status;
    }

    bool LookaheadSize(void){
        return(pAheadSize);
    }

    void LookaheadSize(const int size){
        if(size >0)
        {
            pAheadSize = size;
        }
    }

    int GetCount(void) const{
        return(pCount);
    }

    void SetCount(size_t count){
        if(pCount < count)
		{
			Grow(count - pCount);
		}else if(pIsOwner)
        {
            for(int ct=count;ct<pCount;ct++)
            {
                delete pData[ct];
            }
        }
		pCount = count;
    }

    void Replace(int index, T* Src)
    {
        if(index <0 || index >= pCount)
            return;
        if(pIsOwner)
        {
            delete pData[index];
        }
        pData[index] = Src;
    }

    T* Insert(const int index, const T& data){
#ifdef __WXWINDOWS__
    wxASSERT_MSG(pIsOwner,_T("Must be owner"));
#endif
        T* tmp = new T;
		*tmp = data;
		Insert(index,tmp);
        return(tmp);
    };

    void Insert(const int index, T* src)
    {
        if(index <0 || index > pCount)
            return;
		if(index == pCount)
		{
			Add(src);
			return;
		}
        Add(NULL);
        for(int ct=pCount-1; ct> index; ct--)
            pData[ct] = pData[ct-1];
        pData[index] = src;
    }

    void Set(int index, T* src)
    {
        if(index <0 || index >= pCount)
            return;
        pData[index] = src;
    }

    bool MoveRow(int from, int to)
    {
        if(from < 0 || from >= pCount)
            return(false);
        if(from < 0 || from >= pCount)
            return(false);
        if(from == to)
            return(true);
        T* tempT;
        tempT = pData[from];
        if(to < from)
        {
            for (int idx = from; idx > to; idx--)
            {
                pData[idx] = pData[idx-1];
            }
        }
        else
        {
            for (int idx = from; idx < to; idx++)
            {
                pData[idx] = pData[idx+1];
            }
        }
        pData[to] = tempT;
        return(true);
    }


protected:
    T** pData;
    int pSize;
    int pCount;
    bool pIsOwner;
    int pAheadSize;
};


template <class T>
class GrowArray2 {

public:
    GrowArray2(){
        pCount=0;
        pSize = 0;
        pData = NULL;
        pAheadSize = GROWAHEAD;
        Grow();
    };

    virtual ~GrowArray2(){
        Clear();
        delete[] pData;
    };


    int Add(const T& data){
        if(pCount >= pSize)
            Grow();
        pData[pCount] = data;
        pCount ++;
		return(pCount-1);
    };

    void Add(const T& data, const int number){
        while(pCount + number >= pSize)
        {
            Grow();
        }
        for(int ct=0; ct<number;ct++)
        {
            pData[pCount + ct] = data;
        }
        pCount += number;
		return;
    };

    int Index(const T& data){
        for(int ct=0;ct<pCount;ct++)
        {
            if(data == pData[ct])
                return(ct);
        }
        return(-1);
    }

    void Set(const int index,const T& value){
        if((unsigned int)index >= (unsigned int)pCount)
        {
#ifdef __WXWINDOWS__
            wxTrap();
#endif
            return;
        }
        pData[index] = value;
        return;
    }

    T& operator[](const int index){
        if((unsigned int)index >= (unsigned int)pCount)
        {
#ifdef __WXWINDOWS__
            wxTrap();
#endif
            return(pData[0]);
        }
        return(pData[index]);
    };

    GrowArray2<T>& operator = (GrowArray2<T>& src)
    {
        Clear();
        int n = src.GetCount();
        for(int ct=0;ct < n; ct++)
        {
            Add(src[ct]);
        }
        return(src);
    }


    void Delete(const int index){
        if((unsigned int)index >= (unsigned int)pCount)
            return;
        for(int ct=index;ct<pCount -1;ct++)
            pData[ct] = pData[ct+1];
        pCount --;
    };


    void Clear(void){
        pCount=0;
        delete[] pData;
        pSize=0;
        pData = NULL;
        Grow();
    };

    void Grow(void){
		Grow(pAheadSize);
	}

	void Grow(const unsigned int size)
	{
        pSize += size;
        T* tmp = new T[pSize];
        for(int ct=0;ct<pCount;ct++)
        {
            tmp[ct]=pData[ct];
        }
        if(pData)
            delete[] pData;
        pData = tmp;
    }


    bool LookaheadSize(void){
        return(pAheadSize);
    }

    void LookaheadSize(const int size){
        if(size >0)
        {
            pAheadSize = size;
        }
    }

    int GetCount(void) const{
        return(pCount);
    }


    void Replace(int index, const T& Src)
    {
        if(index <0 || index >= pCount)
            return;
        pData[index] = Src;
    }

/*    void Set(const int index, const T& src)
    {
        if(index <0 || index > pCount)
            return;
		if(index == pCount)
		{
			Add(src);
			return;
		}
        Add(src);
        for(int ct=pCount-1; ct> index; ct--)
            pData[ct] = pData[ct-1];
        pData[index] = src;
    }*/


    void MoveRow(const int from,const int to)
    {
        if(from < 0 || from >= pCount)
            return;
        if(from < 0 || from >= pCount)
            return;
        if(from == to)
            return;
        T tempT;
        tempT = pData[from];
        if(to < from)
        {
            for (int idx = from; idx > to; idx--)
            {
                pData[idx] = pData[idx-1];
            }
        }
        else
        {
            for (int idx = from; idx < to; idx++)
            {
                pData[idx] = pData[idx+1];
            }
        }
        pData[to] = tempT;
    }


protected:
    T* pData;
    int pSize;
    int pCount;
    int pAheadSize;
};


template <class T>
class GrowArray3
{

public:
	GrowArray3(){
        pCount=0;
        pSize = 0;
        pData = NULL;
        pAheadSize = GROWAHEAD;
    };

    virtual ~GrowArray3(){
        Clear();
    };

    T* Add(const T& data){
        if(pCount > pSize-3)
		{
			Grow();
		}
		*pData[pCount] = data;
		pCount++;
		return(pData[pCount-1]);
    };

    int Index(const T* data){
        for(int ct=0;ct<pCount;ct++)
        {
            if(data == pData[ct])
                return(ct);
        }
        return(-1);
    }

    T* operator[](const int index){
        if((unsigned int)index >= (unsigned int)pSize)
		{
            if(index >= pSize +3)
			{
				return(NULL);
			}
			Grow();
		}
        return(pData[index]);
    };

    GrowArray3<T>& operator = (GrowArray3<T>& src)
    {
        Clear();
        int n = src.pCount;
        for(int ct=0;ct < n; ct++)
        {
            Add(*src[ct]);
        }
        return(*this);
    }

    void Delete(const T* ptr){
        Delete(Index(ptr));
    };

    void Delete(const int index){
        if((unsigned int)index >= (unsigned int)pCount)
            return;
		delete pData[index];
        for(int ct=index;ct<pCount -1;ct++)
            pData[ct] = pData[ct+1];
        pCount --;
		pSize --;
    };

    int GetCount(void) const{
        return(pCount);
    }


    void Clear(void){
		for(int ct=0;ct<pSize;ct++)
		{
			delete pData[ct];
		}
        pCount=0;
        delete[] pData;
        pSize=0;
        pData = NULL;
    };

	void Grow(void){Grow(pAheadSize);}

    void Grow(size_t amount){
		int pct=pSize;
        T** tmp = new T*[pSize + amount];
        for(int ct=0;ct<pSize;ct++)
        {
            tmp[ct]=pData[ct];
        }
        pSize += amount;
        if(pData)
            delete[] pData;
        pData = tmp;
		for(;pct<pSize;pct++)
		{
			pData[pct] = new T;
		}
    }

    void LookaheadSize(const int size){
        if(size >4)
        {
            pAheadSize = size;
        }
    }



    void Insert(int index, T& src)
    {
        if(index <0 || index > pCount)
            return;
		if(pCount > pSize-3)
		{
			Grow();
		}
		if(index == pCount)
		{
			*pData[index] = src;
			pCount++;
			return;
		}
        T * tmp = pData[pCount];
		for(int ct=pCount-1; ct> index; ct--)
            pData[ct] = pData[ct-1];
        pData[index] = tmp;
		*tmp = src;
		pCount++;
    }

    void Set(int index, const T& src)
    {
        if(index <0 || index >= pCount)
            wxTrap();
            return;
        *pData[index] = src;
    }


protected:
    T** pData;
    int pSize;
    int pCount;
    int pAheadSize;

};


#endif

